﻿namespace BM.Tools.WebControls.MForm
{
    using System.Collections.Generic;    
    using System.Diagnostics.CodeAnalysis;
    using System.Linq;
    using System.Xml;
    using System.Xml.XPath;

    using BM.Tools.WebControls.MForm.Controls;
    using BM.Tools.WebControls.MForm.Controls.Helper;
    using BM.Tools.WebControls.MForm.Controls.Items;

    /// <summary>
    /// A static class that allows retrieving the XML data out of the form
    /// </summary>
    public static class XmlOutput
    {
        /// <summary>
        /// looks for IXmlEditor objects inside child controls
        /// </summary>
        /// <param name="parent">
        /// The parent.
        /// </param>
        /// <returns>
        /// all children xml editors
        /// </returns>
        public static IEnumerable<IXmlEditor> GetChildrenXmlEditors(this IXmlEditor parent)
        {
            var control = parent as System.Web.UI.Control;
            if (control == null)
            {
                return null;
            }

            return control.Controls.OfType<IXmlEditor>(true).OrderBy(editor => editor.Ordinal);
        }

        /// <summary>
        /// returns the output xml (the node with all the child nodes, wrapped in an XmlDocument) associated with the given OffspringsItem
        /// </summary>
        /// <param name="item">
        /// The offspring item.
        /// </param>
        /// <returns>
        /// the output xml document
        /// </returns>
        [SuppressMessage("Microsoft.Design", "CA1059:MembersShouldNotExposeCertainConcreteTypes", MessageId = "System.Xml.XmlNode", Justification = "Specific functionality provided by the concrete type is required")]
        public static XmlDocument GetOutputXml(this OffspringItem item)
        {
            var outputXml = new XmlDocument();
            item.AppendToParent(outputXml);
            return outputXml;
        }

        /// <summary>
        /// Appends the xml element created from the offspring item to the given parent. 
        /// </summary>
        /// <param name="item">
        /// The offspring item.
        /// </param>
        /// <param name="parent">
        /// The parent.
        /// </param>
        /// <returns>
        /// the appended element
        /// </returns>
        public static IXPathNavigable AppendElement(this OffspringItem item, IXPathNavigable parent)
        {
            var navigator = parent.CreateNavigator();
            navigator.AppendChildElement(item.Basis.Prefix, item.Basis.LocalName, item.Basis.Namespace, null);
            navigator.MoveToChild(item.Basis.LocalName, item.Basis.Namespace);
            while (navigator.MoveToNext())
            {
            }

            return navigator;
        }

        /// <summary>
        /// Appends xml attribute to the specified node.
        /// </summary>
        /// <param name="item">
        /// The offspring item.
        /// </param>
        /// <param name="parent">
        /// The parent node.
        /// </param>        
        internal static void AppendAttribute(this LeafItem item, IXPathNavigable parent)
        {
            var nameSpace = (item.Basis.Root.Manager.DefaultNamespace != item.Basis.Namespace) ? item.Basis.Namespace : null;
            parent.CreateNavigator().CreateAttribute(null, item.Basis.LocalName, nameSpace, item.Value);
        }

        /// <summary>
        /// Appends xml element to the specified node.
        /// </summary>
        /// <param name="item">
        /// The offspring item.
        /// </param>
        /// <param name="parent">
        /// The parent node.
        /// </param>        
        internal static void AppendElement(this LeafItem item, IXPathNavigable parent)
        {
            parent.CreateNavigator().AppendChildElement(item.Basis.Prefix, item.Basis.LocalName, item.Basis.Namespace, item.Value);            
        }

        internal static void AppendNilElement(this LeafItem item, IXPathNavigable parent)
        {
            var navigator = parent.CreateNavigator();            
            navigator.AppendChildElement(item.Basis.Prefix, item.Basis.LocalName, item.Basis.Namespace, null);
            navigator.MoveToChild(XPathNodeType.Element);
            while (navigator.MoveToNext(XPathNodeType.Element))
            {
            }

            navigator.CreateAttribute("xsi", "nil", @"http://www.w3.org/2001/XMLSchema-instance", "true");
        }
    }
}